home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.2 Applications 1996 May / SGI IRIX 6.2 Applications 1996 May.iso / dist / impr_dev.idb / usr / impressario / src / scan / file / scan.c.z / scan.c
C/C++ Source or Header  |  1996-05-06  |  46KB  |  1,683 lines

  1. /*
  2.  * scan.c
  3.  *
  4.  *     Scanner specific module of a scanner driver for scanning from
  5.  *     SGI image files.  This driver supports greyscale and rgb
  6.  *     versions of the SGI image file.
  7.  *
  8.  *      If you are writing a scanner driver, please refer to the
  9.  *      comments in the template version of scan.c for more
  10.  *      information about what is going on here.  Also, look in
  11.  *      /usr/include/imp.h and the libimp(3) manual page for the
  12.  *      interface that this module uses to deal with SGI image files.
  13.  *
  14.  * Copyright 1992, 1993 Silicon Graphics, Inc.
  15.  * All Rights Reserved.
  16.  *
  17.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  18.  * the contents of this file may not be disclosed to third parties, copied or
  19.  * duplicated in any form, in whole or in part, without the prior written
  20.  * permission of Silicon Graphics, Inc.
  21.  *
  22.  * RESTRICTED RIGHTS LEGEND:
  23.  * Use, duplication or disclosure by the Government is subject to restrictions
  24.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  25.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  26.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  27.  * rights reserved under the Copyright Laws of the United States.
  28.  */
  29.  
  30. #include <sys/types.h>
  31. #include <sys/times.h>
  32. #include <sys/param.h>
  33. #include <sys/prctl.h>
  34. #include <sys/wait.h>
  35.  
  36. #include <stdio.h>
  37. #include <dslib.h>
  38. #include <fcntl.h>
  39. #include <errno.h>
  40. #include <string.h>
  41. #include <bstring.h>
  42. #include <signal.h>
  43. #include <stdlib.h>
  44. #include <invent.h>
  45. #include <unistd.h>
  46. #include <imp.h>
  47. #include <locale.h>
  48.  
  49. #include <msgs/uxsgiimpr.h>
  50.  
  51. #include <scanner.h>
  52. #include <scandrv.h>
  53.  
  54. #include "scan.h"
  55. #include "main.h"
  56.  
  57. /*
  58.  * Stuff for converting from color images to greyscale
  59.  */
  60. #define RINTLUM (77)
  61. #define GINTLUM (150)
  62. #define BINTLUM (29)
  63. #define ILUM(r,g,b)     ((RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
  64. #define ILUM16(r,g,b)   ((RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b)))
  65.  
  66. /*
  67.  * Stuff from converting from greyscale to monochrome
  68.  */
  69. #define THRESH(val,thresh) ((val) > (thresh) ? 1 : 0)
  70. #define THRESHVAL 128
  71.  
  72. /*
  73.  * Scale a pixel from 2 bytes to 1 byte
  74.  */
  75. #define SCALE(pixel) (((pixel * 255) / (imgMaxValue - imgMinValue)) & 0xff)
  76.  
  77. /*
  78.  * imgOffset and imgStride are global variables used in the conversion
  79.  * functions.  imgOffset is the number of pixels in each row to skip
  80.  * while converting, and imgStride is the number of pixels in each row.
  81.  *
  82.  * The reason we do this is that the libimp interface gives us image
  83.  * data a row at a time, and the scan interface requires us to crop
  84.  * the scanned area.  We do the cropping at the same time that we
  85.  * convert the data to a format that fits into the scan interface spec
  86.  * so that we only need to do one pass of conversion over each row.
  87.  * This all gets done in the DoImgProc thread, which calls our convert
  88.  * function for each row (see SetupScan below).
  89.  */
  90. static int imgOffset, imgStride;
  91.  
  92. /*
  93.  * Temporary memory for holding rows being scaled down from 16 bits to
  94.  * 8 bit.
  95.  */
  96. static void *imgTempBuf = NULL;
  97.  
  98. /*
  99.  * These global variables get used by the function that scales 16 bit
  100.  * per pixel data down to 8 bit pixel data.
  101.  */
  102. static long imgMaxValue, imgMinValue;
  103.  
  104. /*
  105.  * Pointer to a function for getting rows of data from the image file.
  106.  * We use this level of indirection to avoid having to do a
  107.  * complicated if test in DoScan; instead, we do all the testing we
  108.  * need in SetupScan and set imgGetRows appropriately.
  109.  */
  110. static int (*imgGetRows)(IMPImage *img, short y, short z,
  111.              void *buf, int nrows);
  112.  
  113. /*
  114.  *  static int
  115.  *  HowManyBits(unsigned short maxVal)
  116.  *
  117.  *  Description:
  118.  *      Figure out how many bits need to be used to represent maxVal
  119.  *
  120.  *  Parameters:
  121.  *      maxVal
  122.  *
  123.  *  Returns:
  124.  *      The number of bits necessary to represent maxVal
  125.  */
  126.  
  127. static int
  128. HowManyBits(unsigned short maxVal)
  129. {
  130.     int i;
  131.  
  132.     /*
  133.      * You still need at least a bit to represent all 0's.
  134.      */
  135.     if (!maxVal) {
  136.     return 1;
  137.     }
  138.  
  139.     i = 0;
  140.     while (maxVal) {
  141.     i++;
  142.     maxVal >>= 1;
  143.     }
  144.     return i;
  145. }
  146.  
  147. /*
  148.  *  SCANINFO *
  149.  *  OpenScanner(char *dev)
  150.  *
  151.  *  Description:
  152.  *      Get a SCANINFO structure for the scanner connected to dev.
  153.  *      This opens the device and does an inquiry to find out what
  154.  *      kind of scanner is attached.  If it's one we know about, we
  155.  *      allocate a SCANINFO structure, fill it in, and return it.
  156.  *
  157.  *  Parameters:
  158.  *      dev  device for the scanner
  159.  *
  160.  *  Returns:
  161.  *      pointer to a SCANATTRIB if successful, NULL with drverr set if
  162.  *      failure.
  163.  */
  164.  
  165. SCANINFO *
  166. OpenScanner(char *dev)
  167. {
  168.     static SCANINFO scan;
  169.     IMPImage *img;
  170.     static SCDATATYPE rgb8types[] = {
  171.     { SC_PACKPLANE, 3, SC_RGB, 8 },  /* planar RGB */
  172.     { SC_PACKPIX, 3, SC_RGB, 8 },    /* pixel packed RGB */
  173.     { SC_PACKPIX, 1, SC_GREY, 8 },   /* 8 bit grey scale */
  174.     { SC_PACKPIX, 1, SC_MONO, 1 },   /* 8 black and white */
  175.     }; 
  176.     static SCDATATYPE rgb16types[] = {
  177.     { SC_PACKPLANE, 3, SC_RGB, 16 }, /* > 8 bit planar RGB */
  178.     { SC_PACKPIX, 3, SC_RGB, 16 },   /* > 8 bit pixel packed RGB */
  179.     { SC_PACKPLANE, 3, SC_RGB, 8 },  /* planar RGB */
  180.     { SC_PACKPIX, 3, SC_RGB, 8 },    /* pixel packed RGB */
  181.     { SC_PACKPIX, 1, SC_GREY, 16 },  /* > 8 bit grey scale */
  182.     { SC_PACKPIX, 1, SC_GREY, 8 },   /* 8 bit grey scale */
  183.     { SC_PACKPIX, 1, SC_MONO, 1 },   /* 8 black and white */
  184.     }; 
  185.     static SCDATATYPE grey8types[] = {
  186.     { SC_PACKPIX, 1, SC_GREY, 8 },   /* 8 bit grey scale */
  187.     { SC_PACKPIX, 1, SC_GREY, 8 },   /* 8 bit grey scale */
  188.     { SC_PACKPIX, 1, SC_MONO, 1 },   /* 8 black and white */
  189.     }; 
  190.     static SCDATATYPE grey16types[] = {
  191.     { SC_PACKPIX, 1, SC_GREY, 16 },  /* 8 bit grey scale */
  192.     { SC_PACKPIX, 1, SC_GREY, 8 },   /* 8 bit grey scale */
  193.     { SC_PACKPIX, 1, SC_MONO, 1 },   /* 8 black and white */
  194.     }; 
  195.     static float res = 100;              /* set resolution somewhat */
  196.                      /* arbitrarily to 100 */
  197.     static char errorBuf[SC_MAXERRSTR];
  198.     char tmpFile[MAXPATHLEN], *tmpDir;
  199.     int bits;
  200.     struct sigaction act, oact;
  201.     pid_t pid;
  202.     int fd, status;
  203.  
  204.     /*
  205.      * Check for file existence before calling impOpen.
  206.      */
  207.     if (access(dev, F_OK | R_OK) != 0) {
  208.     drverr = errno;
  209.     return NULL;
  210.     }
  211.  
  212.     img = impOpen(dev, "r");
  213.  
  214.     /*
  215.      * If the open failed, try using imgcopy to convert the file to
  216.      * SGI format.
  217.      */
  218.     if (!img) {
  219.     drvmsg = impErrorString(IMPerrno);
  220.     drverr = SCEDRVMSG;
  221.  
  222.     /*
  223.      * Create a temp name for use in storing the converted file
  224.      */
  225.     tmpDir = getenv("TMPDIR");
  226.     if (!tmpDir) {
  227.         tmpDir = "/var/tmp";
  228.     }
  229.     (void)sprintf(tmpFile, "%s/fileXXXXXX", tmpDir);
  230.     (void)mktemp(tmpFile);
  231.  
  232.     act.sa_handler = SIG_DFL;
  233.     act.sa_flags = 0;
  234.     (void)sigemptyset(&act.sa_mask);
  235.     (void)sigaction(SIGCHLD, &act, &oact);
  236.     
  237.     pid = fork();
  238.  
  239.     /*
  240.      * Child runs imgcopy
  241.      */
  242.     if (pid == 0) {
  243.         for (fd = getdtablesize(); fd > 2; fd--) {
  244.         (void)close(fd);
  245.         }
  246.         /*
  247.          * Point stderr to /dev/null to get rid of obnoxious error
  248.          * messsages on terminal
  249.          */
  250.         (void)close(2);
  251.         (void)open("/dev/null", O_WRONLY);
  252.         (void)execlp("imgcopy", "imgcopy", "-fSGI", dev, tmpFile, NULL);
  253.         exit(-1);
  254.     }
  255.  
  256.     /*
  257.      * Parent waits for child, and then tries to open the
  258.      * converted file if imgcopy exits with a 0 status
  259.      */
  260.     if (pid > 0) {
  261.         if ((pid = waitpid(pid, &status, 0)) == pid
  262.         && WIFEXITED(status) && WEXITSTATUS(status) == 0) {
  263.         img = impOpen(tmpFile, "r");
  264.         }
  265.     }
  266.  
  267.     /*
  268.      * unlink the tmpFile so it doesn't hang around after we're
  269.      * done.  We've still got it open, though, and img is our
  270.      * pointer into it.
  271.      */
  272.     (void)unlink(tmpFile);
  273.     (void)sigaction(SIGCHLD, &oact, NULL);
  274.  
  275.     if (!img) {
  276.         return NULL;
  277.     } else {
  278.         /*
  279.          * If we succeeded we have to reset drverr or an error
  280.          * will get reported.
  281.          */
  282.         drverr = 0;
  283.     }
  284.     }
  285.  
  286.     if (impNumChannels(img) < 3 && impNumChannels(img) != 1) {
  287.     (void)sprintf(errorBuf,
  288.               gettxt(_SGI_FILESCAN_BADTYPE,
  289.                  "Can't figure out what type of image "
  290.                  "file %s is\n"), dev);
  291.     drvmsg = errorBuf;
  292.     drverr = SCEDRVMSG;
  293.     return NULL;
  294.     }
  295.  
  296.     if (impRasterBPP(img) != 1 && impRasterBPP(img) != 2) {
  297.     (void)sprintf(errorBuf,
  298.               gettxt(_SGI_FILESCAN_WEIRDBPP,
  299.                  "%s has a weird number of bytes per pixel (%d)"),
  300.               dev, impRasterBPP(img));
  301.     drvmsg = errorBuf;
  302.     drverr = SCEDRVMSG;
  303.     return NULL;
  304.     }
  305.     
  306.     if (impRasterBPP(img) == 2) {
  307.     bits = HowManyBits(impMaxValue(img));
  308.     imgMaxValue = impMaxValue(img);
  309.     imgMinValue = impMinValue(img);
  310.     }
  311.         
  312.     /*
  313.      * If num channels is 3, it's an rgb image.  If it's 1, it's a greyscale
  314.      * image.  Otherwise, it's a mystery to us.
  315.      */
  316.     if (impNumChannels(img) >= 3) {
  317.     /*
  318.      * The impMaxValue test keeps us out of a situation in which
  319.      * we give bad info to the scan app when we have a strange
  320.      * image file that uses 2 bytes per pixel but doesn't use the
  321.      * high bytes at all.
  322.      */
  323.     if (impRasterBPP(img) == 1 || impMaxValue(img) <= 255) {
  324.         scan.types = rgb8types;
  325.         scan.ntypes = sizeof rgb8types/sizeof *rgb8types;
  326.     } else {
  327.         scan.types = rgb16types;
  328.         scan.ntypes = sizeof rgb16types/sizeof *rgb16types;
  329.         rgb16types[0].bpp = rgb16types[1].bpp = rgb16types[4].bpp = bits;
  330.     }
  331.     } else if (impNumChannels(img) == 1) {
  332.     if (impRasterBPP(img) == 1 || impMaxValue(img) <= 255) {
  333.         scan.types = grey8types;
  334.         scan.ntypes = sizeof grey8types/sizeof *grey8types;
  335.     } else {
  336.         scan.types = grey16types;
  337.         scan.ntypes = sizeof grey16types/sizeof *grey16types;
  338.         grey16types[0].bpp = bits;
  339.     }
  340.     } else {
  341.     drverr = SCENOTSUPPORTED;
  342.     return NULL;
  343.     }
  344.  
  345.     /*
  346.      * This tells main.c that we only support one resolution in
  347.      * "hardware", 100.  We set min and max to allow for impulse
  348.      * zooming main.c can do in cooperation with us to achieve other
  349.      * resolutions.
  350.      */
  351.     scan.metric = SC_INCHES;
  352.     scan.nres = 1;
  353.     scan.xres = scan.yres = &res;
  354.  
  355.     scan.minxres = scan.minyres = 1;
  356.     scan.maxxres = scan.maxyres = 2 * res;
  357.  
  358.     scan.pagex = 0;
  359.     scan.pagey = 0;
  360.     scan.pagewidth = impXSize(img) / res;
  361.     scan.pageheight = impYSize(img) / res;
  362.  
  363.     scan.priv = img;
  364.     return &scan;
  365. }
  366.  
  367. /*
  368.  * Conversion functions.
  369.  *
  370.  * The following functions convert from the four libimp formats that
  371.  * we support (rgb and greyscale, 1 byte and 2 bytes per pixel) to the
  372.  * seven scanner interface formats that we support (planar rgb 8,
  373.  * planar rgb 16, chunky rgb 8, chunky rgb 16, greyscale 8, greyscale
  374.  * 16, and mono).  (If the image file is in greyscale format, we don't
  375.  * convert to color)
  376.  *
  377.  * All conversion takes place in the DoImgProc thread using the
  378.  * "convert" member of the SCANPARAMS structure passed in to
  379.  * SetupScan.  In SetupScan we set params->convert to point to the
  380.  * appropriate conversion function given the type of image file we're
  381.  * dealing with and the data type that we've been requested to provide.
  382.  */
  383.  
  384. /*
  385.  *  static void
  386.  *  RGB8ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
  387.  *
  388.  *  Description:
  389.  *      Convert a row of banded 8 bit/channel RGB image data to a row
  390.  *      of chunky 8 bit/channel RGB image data, cropping as necessary.
  391.  *
  392.  *  Parameters:
  393.  *      frombuf  Banded RGB data from image file, 8 bits/pixel/channel
  394.  *      fromx    In theory, the width of fromx.  In actuality,
  395.  *               imgStride is the width of frombuf and fromx is what
  396.  *               we set params->xpixels to in SetupScan to make the
  397.  *               main.c module set up zmap right if we're zooming.
  398.  *      tobuf    8 bit/channel chunky RGB data
  399.  *      tox      width of tox
  400.  *      zmap     Zoom map for impulse zoom
  401.  */
  402.  
  403. /*ARGSUSED*/
  404. static void
  405. RGB8ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
  406. {
  407.     register unsigned char *r, *g, *b;
  408.     register unsigned char *t = tobuf;
  409.     register int x, fx;
  410.  
  411.     /*
  412.      * We're cropping the data as well as converting and zooming it.
  413.      * We skip imgOffset pixels in each channel.  imgStride is the
  414.      * number of pixels per channel that we actually read from the
  415.      * image file.
  416.      */
  417.     r = (char *)frombuf + imgOffset;
  418.     g = r + imgStride;
  419.     b = g + imgStride;
  420.  
  421.     /*
  422.      * The zmap test is outside the loops rather than having one loop
  423.      * with the zmap test because we want to reduce the amount of
  424.      * processing per pixel as much as possible.
  425.      */
  426.     if (zmap) {
  427.     for (x = 0; x < tox; x++) {
  428.         fx = zmap[x];
  429.         *t++ = r[fx];
  430.         *t++ = g[fx];
  431.         *t++ = b[fx];
  432.     }
  433.     } else {
  434.     while (tox--) {
  435.         *t++ = *r++;
  436.         *t++ = *g++;
  437.         *t++ = *b++;
  438.     }
  439.     }
  440. }
  441.  
  442. /*
  443.  *  static void
  444.  *  RGB16ToChunky16(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
  445.  *
  446.  *  Description:
  447.  *      Convert a row of banded 16 bit/channel RGB image data to a row
  448.  *      of chunky 16 bit/channel RGB image data, cropping as necessary.
  449.  *
  450.  *  Parameters:
  451.  *      frombuf  Banded RGB data from image file, 16 bits/pixel/channel
  452.  *      fromx    In theory, the width of fromx.  In actuality,
  453.  *               imgStride is the width of frombuf and fromx is what
  454.  *               we set params->xpixels to in SetupScan to make the
  455.  *               main.c module set up zmap right if we're zooming.
  456.  *      tobuf    16 bit/channel chunky RGB data
  457.  *      tox      width of tox
  458.  *      zmap     Zoom map for impulse zoom
  459.  */
  460.  
  461. /*ARGSUSED*/
  462. static void
  463. RGB16ToChunky16(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
  464. {
  465.     register unsigned short *r, *g, *b;
  466.     register unsigned short *t = tobuf;
  467.     register int x, fx;
  468.  
  469.     /*
  470.      * We're cropping the data as well as converting and zooming it.
  471.      * We skip imgOffset pixels in each channel.  imgStride is the
  472.      * number of pixels per channel that we actually read from the
  473.      * image file.
  474.      */
  475.     r = (unsigned short *)frombuf + imgOffset;
  476.     g = r + imgStride;
  477.     b = g + imgStride;
  478.  
  479.     /*
  480.      * The zmap test is outside the loops rather than having one loop
  481.      * with the zmap test because we want to reduce the amount of
  482.      * processing per pixel as much as possible.
  483.      */
  484.     if (zmap) {
  485.     for (x = 0; x < tox; x++) {
  486.         fx = zmap[x];
  487.         *t++ = r[fx];
  488.         *t++ = g[fx];
  489.         *t++ = b[fx];
  490.     }
  491.     } else {
  492.     while (tox--) {
  493.         *t++ = *r++;
  494.         *t++ = *g++;
  495.         *t++ = *b++;
  496.     }
  497.     }
  498. }
  499.  
  500. /*
  501.  *  static void
  502.  *  RGB16ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
  503.  *
  504.  *  Description:
  505.  *      Convert a row of banded 16 bit/channel RGB image data to a row
  506.  *      of chunky 8 bit/channel RGB image data, cropping as necessary.
  507.  *
  508.  *  Parameters:
  509.  *      frombuf  Banded RGB data from image file, 16 bits/pixel/channel
  510.  *      fromx    In theory, the width of fromx.  In actuality,
  511.  *               imgStride is the width of frombuf and fromx is what
  512.  *               we set params->xpixels to in SetupScan to make the
  513.  *               main.c module set up zmap right if we're zooming.
  514.  *      tobuf    8 bit/channel chunky RGB data
  515.  *      tox      width of tox
  516.  *      zmap     Zoom map for impulse zoom
  517.  */
  518.  
  519. /*ARGSUSED*/
  520. static void
  521. RGB16ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
  522. {
  523.     register unsigned short *r, *g, *b;
  524.     register unsigned char *t = tobuf;
  525.     register int x, fx;
  526.  
  527.     /*
  528.      * We're cropping the data as well as converting and zooming it.
  529.      * We skip imgOffset pixels in each channel.  imgStride is the
  530.      * number of pixels per channel that we actually read from the
  531.      * image file.
  532.      */
  533.     r = (unsigned short *)frombuf + imgOffset;
  534.     g = r + imgStride;
  535.     b = g + imgStride;
  536.  
  537.     /*
  538.      * The zmap test is outside the loops rather than having one loop
  539.      * with the zmap test because we want to reduce the amount of
  540.      * processing per pixel as much as possible.
  541.      */
  542.     if (zmap) {
  543.     for (x = 0; x < tox; x++) {
  544.         fx = zmap[x];
  545.         *t++ = SCALE(r[fx]);
  546.         *t++ = SCALE(g[fx]);
  547.         *t++ = SCALE(b[fx]);
  548.     }
  549.     } else {
  550.     while (tox--) {
  551.         *t++ = SCALE(*r++);
  552.         *t++ = SCALE(*g++);
  553.         *t++ = SCALE(*b++);
  554.     }
  555.     }
  556. }
  557.  
  558. /*
  559.  *  static void
  560.  *  CropRow8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
  561.  *
  562.  *  Description:
  563.  *      Crop a row of image data.  This function is used when scanning
  564.  *      planar RGB from a color image file or when scanning greyscale
  565.  *      from a greyscale image file.
  566.  *
  567.  *  Parameters:
  568.  *      frombuf  8 bits/channel image data
  569.  *      fromx    In theory, the width of fromx.  In actuality,
  570.  *               imgStride is the width of frombuf and fromx is what
  571.  *               we set params->xpixels to in SetupScan to make the
  572.  *               main.c module set up zmap right if we're zooming.
  573.  *      tobuf    8 bits/channel cropped image data
  574.  *      tox      width of tox
  575.  *      zmap     Zoom map for impulse zoom
  576.  */
  577.  
  578. /*ARGSUSED*/
  579. static void
  580. CropRow8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
  581. {
  582.     register char *s = (char *)fromBuf + imgOffset;
  583.     register unsigned char *t = toBuf;
  584.     register int x;
  585.  
  586.     if (zmap) {
  587.     for (x = 0; x < tox; x++) {
  588.         *t++ = s[zmap[x]];
  589.     }
  590.     } else {
  591.     while (tox--) {
  592.         *t++ = *s++;
  593.     }
  594.     }
  595. }
  596.  
  597. /*
  598.  *  static void
  599.  *  CropRow16(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
  600.  *
  601.  *  Description:
  602.  *      Crop a row of image data.  This function is used when scanning
  603.  *      planar RGB from a color image file or when scanning greyscale
  604.  *      from a greyscale image file.
  605.  *
  606.  *  Parameters:
  607.  *      frombuf  16 bits/channel image data
  608.  *      fromx    In theory, the width of fromx.  In actuality,
  609.  *               imgStride is the width of frombuf and fromx is what
  610.  *               we set params->xpixels to in SetupScan to make the
  611.  *               main.c module set up zmap right if we're zooming.
  612.  *      tobuf    16 bits/channel cropped image data
  613.  *      tox      width of tox
  614.  *      zmap     Zoom map for impulse zoom
  615.  */
  616.  
  617. /*ARGSUSED*/
  618. static void
  619. CropRow16(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
  620. {
  621.     register unsigned short *s = (unsigned short *)fromBuf + imgOffset;
  622.     register unsigned short *t = toBuf;
  623.     register int x;
  624.  
  625.     if (zmap) {
  626.     for (x = 0; x < tox; x++) {
  627.         *t++ = s[zmap[x]];
  628.     }
  629.     } else {
  630.     while (tox--) {
  631.         *t++ = *s++;
  632.     }
  633.     }
  634. }
  635.  
  636. /*
  637.  *  static void
  638.  *  CropRow16To8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
  639.  *
  640.  *  Description:
  641.  *      Crop a row of image data.  This function is used when scanning
  642.  *      planar RGB from a color image file or when scanning greyscale
  643.  *      from a greyscale image file.
  644.  *
  645.  *  Parameters:
  646.  *      frombuf  16 bits/channel image data
  647.  *      fromx    In theory, the width of fromx.  In actuality,
  648.  *               imgStride is the width of frombuf and fromx is what
  649.  *               we set params->xpixels to in SetupScan to make the
  650.  *               main.c module set up zmap right if we're zooming.
  651.  *      tobuf    8 bits/channel cropped image data
  652.  *      tox      width of tox
  653.  *      zmap     Zoom map for impulse zoom
  654.  */
  655.  
  656. /*ARGSUSED*/
  657. static void
  658. CropRow16To8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
  659. {
  660.     register unsigned short *s = (unsigned short *)fromBuf + imgOffset;
  661.     register unsigned char *t = toBuf;
  662.     register int x;
  663.  
  664.     if (zmap) {
  665.     for (x = 0; x < tox; x++) {
  666.         *t++ = SCALE(s[zmap[x]]);
  667.     }
  668.     } else {
  669.     while (tox--) {
  670.         *t++ = SCALE(*s++);
  671.     }
  672.     }
  673. }
  674.  
  675. /*
  676.  *  static void
  677.  *  RGB8ToGrey8(void *frombuf, int fromx, void *tobuf, 
  678.  *              register int tox, int *zmap)
  679.  *
  680.  *  Description:
  681.  *      Convert a row of RGB banded data to greyscale.  This involves
  682.  *      adding together the illumination contributions of each of the
  683.  *      red, green, and blue channels of information.
  684.  *
  685.  *  Parameters:
  686.  *      frombuf  Banded RGB data from image file, 8 bits/pixel/channel
  687.  *      fromx    In theory, the width of fromx.  In actuality,
  688.  *               imgStride is the width of frombuf and fromx is what
  689.  *               we set params->xpixels to in SetupScan to make the
  690.  *               main.c module set up zmap right if we're zooming.
  691.  *      tobuf    8 bit greyscale data
  692.  *      tox      width of tox
  693.  *      zmap     Zoom map for impulse zoom
  694.  */
  695.  
  696. /*ARGSUSED*/
  697. static void
  698. RGB8ToGrey8(void *frombuf, int fromx, void *tobuf, 
  699.       register int tox, int *zmap)
  700. {
  701.     register char *r, *g, *b;
  702.     register unsigned char *t = tobuf;
  703.     register int z;
  704.  
  705.     r = (char *)frombuf + imgOffset;
  706.     g = r + imgStride;
  707.     b = g + imgStride;
  708.  
  709.     if (zmap) {
  710.     while (tox--) {
  711.         z = *zmap++;
  712.         *t++ = ILUM(r[z], g[z], b[z]);
  713.     }
  714.     } else {
  715.     while (tox--) {
  716.         *t++ = ILUM(*r++, *g++, *b++);
  717.     }
  718.     }
  719. }
  720.  
  721. /*
  722.  *  static void
  723.  *  RGB16ToGrey16(void *frombuf, int fromx, void *tobuf, 
  724.  *                register int tox, int *zmap)
  725.  *
  726.  *  Description:
  727.  *      Convert a row of RGB banded data to greyscale.  This involves
  728.  *      adding together the illumination contributions of each of the
  729.  *      red, green, and blue channels of information.
  730.  *
  731.  *  Parameters:
  732.  *      frombuf  Banded RGB data from image file, 16 bits/pixel/channel
  733.  *      fromx    In theory, the width of fromx.  In actuality,
  734.  *               imgStride is the width of frombuf and fromx is what
  735.  *               we set params->xpixels to in SetupScan to make the
  736.  *               main.c module set up zmap right if we're zooming.
  737.  *      tobuf    16 bit greyscale data
  738.  *      tox      width of tox
  739.  *      zmap     Zoom map for impulse zoom
  740.  */
  741.  
  742. /*ARGSUSED*/
  743. static void
  744. RGB16ToGrey16(void *frombuf, int fromx, void *tobuf, 
  745.           register int tox, int *zmap)
  746. {
  747.     register unsigned short *r, *g, *b;
  748.     register unsigned short *t = tobuf;
  749.     register int z;
  750.  
  751.     r = (unsigned short *)frombuf + imgOffset;
  752.     g = r + imgStride;
  753.     b = g + imgStride;
  754.  
  755.     if (zmap) {
  756.     while (tox--) {
  757.         z = *zmap++;
  758.         *t++ = ILUM(r[z], g[z], b[z]);
  759.     }
  760.     } else {
  761.     while (tox--) {
  762.         *t++ = ILUM(*r++, *g++, *b++);
  763.     }
  764.     }
  765. }
  766.  
  767. /*
  768.  *  static void
  769.  *  RGB16ToGrey8(void *frombuf, int fromx, void *tobuf, 
  770.  *                register int tox, int *zmap)
  771.  *
  772.  *  Description:
  773.  *      Convert a row of RGB banded data to greyscale.  This involves
  774.  *      adding together the illumination contributions of each of the
  775.  *      red, green, and blue channels of information.
  776.  *
  777.  *  Parameters:
  778.  *      frombuf  Banded RGB data from image file, 16 bits/pixel/channel
  779.  *      fromx    In theory, the width of fromx.  In actuality,
  780.  *               imgStride is the width of frombuf and fromx is what
  781.  *               we set params->xpixels to in SetupScan to make the
  782.  *               main.c module set up zmap right if we're zooming.
  783.  *      tobuf    8 bit greyscale data
  784.  *      tox      width of tox
  785.  *      zmap     Zoom map for impulse zoom
  786.  */
  787.  
  788. /*ARGSUSED*/
  789. static void
  790. RGB16ToGrey8(void *frombuf, int fromx, void *tobuf, 
  791.          register int tox, int *zmap)
  792. {
  793.     register unsigned short *r, *g, *b;
  794.     register unsigned char *t = tobuf;
  795.     register int z;
  796.  
  797.     r = (unsigned short *)frombuf + imgOffset;
  798.     g = r + imgStride;
  799.     b = g + imgStride;
  800.  
  801.     if (zmap) {
  802.     while (tox--) {
  803.         z = *zmap++;
  804.         *t++ = SCALE(ILUM(r[z], g[z], b[z]));
  805.     }
  806.     } else {
  807.     while (tox--) {
  808.         *t++ = SCALE(ILUM(*r++, *g++, *b++));
  809.     }
  810.     }
  811. }
  812.  
  813. /*
  814.  *  static void
  815.  *  ScaleRow(void *from, void *to, register int width)
  816.  *
  817.  *  Description:
  818.  *      Scale row is used by functions that convert from 2 byte per
  819.  *      pixel data to 1 byte per pixel data.  First, the data is
  820.  *      scaled, and then the appropriate conversion takes place.
  821.  *
  822.  *  Parameters:
  823.  *      from   source row
  824.  *      to     destination row
  825.  *      width  width of row in pixels
  826.  */
  827.  
  828. static void
  829. ScaleRow(void *from, void *to, register int width)
  830. {
  831.     register unsigned char *c = (unsigned char *)to + imgOffset;
  832.     register unsigned short *s = (unsigned short *)from + imgOffset;
  833.  
  834.     while (width--) {
  835.     *c++ = SCALE(*s++);
  836.     }
  837. }
  838.  
  839. /*
  840.  *  static void
  841.  *  ScaleRowRGB(void *from, void *to, int width)
  842.  *
  843.  *  Description:
  844.  *      Scale row is used by functions that convert from 2 byte per
  845.  *      pixel data to 1 byte per pixel data.  First, the data is
  846.  *      scaled, and then the appropriate conversion takes place.
  847.  *
  848.  *  Parameters:
  849.  *      from   source row
  850.  *      to     destination row
  851.  *      width  width of row in pixels
  852.  */
  853.  
  854. static void
  855. ScaleRowRGB(void *from, void *to,int width)
  856. {
  857.     register unsigned char *c = (unsigned char *)to + imgOffset;
  858.     register unsigned short *s = (unsigned short *)from + imgOffset;
  859.     register int x = width;
  860.  
  861.     while (x--) {
  862.     *c++ = SCALE(*s++);
  863.     }
  864.  
  865.     x = width;
  866.     c += imgStride - width;
  867.     s += imgStride - width;
  868.  
  869.     while (x--) {
  870.     *c++ = SCALE(*s++);
  871.     }
  872.  
  873.     x = width;
  874.     c += imgStride - width;
  875.     s += imgStride - width;
  876.  
  877.     while (x--) {
  878.     *c++ = SCALE(*s++);
  879.     }
  880. }
  881.  
  882. /*
  883.  *  static void
  884.  *  RGB8ToMono(void *frombuf, int fromx,
  885.  *            void *tobuf, register int tox, int *zmap)
  886.  *
  887.  *  Description:
  888.  *      Convert a row of RGB banded data to monochrome by calculating
  889.  *      the illumination contributions of each channel and then
  890.  *      thresholding the result.
  891.  *
  892.  *  Parameters:
  893.  *      frombuf  Banded RGB data from image file, 8 bits/pixel/channel
  894.  *      fromx    In theory, the width of fromx.  In actuality,
  895.  *               imgStride is the width of frombuf and fromx is what
  896.  *               we set params->xpixels to in SetupScan to make the
  897.  *               main.c module set up zmap right if we're zooming.
  898.  *      tobuf    1 bit monochrome data
  899.  *      tox      width of tox
  900.  *      zmap     Zoom map for impulse zoom
  901.  */
  902.  
  903. static void
  904. RGB8ToMono(void *frombuf, int fromx, void *tobuf, register int tox, int *zmap)
  905. {
  906.     register char *r, *g, *b;
  907.     register unsigned char *t = tobuf;
  908.     int x, endx, shift;
  909.  
  910.     r = (char *)frombuf + imgOffset;
  911.     g = r + imgStride;
  912.     b = g + imgStride;
  913.  
  914.     if (fromx == tox) {
  915.     while (tox >= 8) {
  916.         *t++ = THRESH(ILUM(r[0], g[0], b[0]), THRESHVAL) << 7 |
  917.         THRESH(ILUM(r[1], g[1], b[1]), THRESHVAL) << 6 |
  918.         THRESH(ILUM(r[2], g[2], b[2]), THRESHVAL) << 5 |
  919.         THRESH(ILUM(r[3], g[3], b[3]), THRESHVAL) << 4 |
  920.         THRESH(ILUM(r[4], g[4], b[4]), THRESHVAL) << 3 |
  921.         THRESH(ILUM(r[5], g[5], b[5]), THRESHVAL) << 2 |
  922.         THRESH(ILUM(r[6], g[6], b[6]), THRESHVAL) << 1 |
  923.         THRESH(ILUM(r[7], g[7], b[7]), THRESHVAL);
  924.         tox -= 8;
  925.         r += 8;
  926.         g += 8;
  927.         b += 8;
  928.     }
  929.  
  930.     *t = 0;
  931.     while (tox--) {
  932.         *t |= THRESH(ILUM(r[tox], g[tox], b[tox]), THRESHVAL) << (7 - tox);
  933.     }
  934.     } else {
  935.     register int x0, x1, x2, x3, x4, x5, x6, x7;
  936.     int endx = tox & ~7;
  937.     for (x = 0; x < endx; x += 8) {
  938.         x0 = zmap[x];
  939.         x1 = zmap[x + 1];
  940.         x2 = zmap[x + 2];
  941.         x3 = zmap[x + 3];
  942.         x4 = zmap[x + 4];
  943.         x5 = zmap[x + 5];
  944.         x6 = zmap[x + 6];
  945.         x7 = zmap[x + 7];
  946.         *t++ = THRESH(ILUM(r[x0], g[x0], b[x0]), THRESHVAL) << 7 |
  947.         THRESH(ILUM(r[x1], g[x1], b[x1]), THRESHVAL) << 6 |
  948.         THRESH(ILUM(r[x2], g[x2], b[x2]), THRESHVAL) << 5 |
  949.         THRESH(ILUM(r[x3], g[x3], b[x3]), THRESHVAL) << 4 |
  950.         THRESH(ILUM(r[x4], g[x4], b[x4]), THRESHVAL) << 3 |
  951.         THRESH(ILUM(r[x5], g[x5], b[x5]), THRESHVAL) << 2 |
  952.         THRESH(ILUM(r[x6], g[x6], b[x6]), THRESHVAL) << 1 |
  953.         THRESH(ILUM(r[x7], g[x7], b[x7]), THRESHVAL);
  954.     }
  955.  
  956.     shift = 7;
  957.     *t = 0;
  958.     while (x < tox) {
  959.         *t |= THRESH(ILUM(r[zmap[x]], g[zmap[x]], b[zmap[x]]),
  960.              THRESHVAL) << shift;
  961.         x++;
  962.         shift--;
  963.     }
  964.     }
  965. }
  966.  
  967. /*
  968.  *  static void
  969.  *  RGB16ToMono(void *frombuf, int fromx,
  970.  *              void *tobuf, register int tox, int *zmap)
  971.  *
  972.  *  Description:
  973.  *      Convert a row of RGB banded data to monochrome by calculating
  974.  *      the illumination contributions of each channel and then
  975.  *      thresholding the result.
  976.  *
  977.  *  Parameters:
  978.  *      frombuf  Banded RGB data from image file, 16 bits/pixel/channel
  979.  *      fromx    In theory, the width of fromx.  In actuality,
  980.  *               imgStride is the width of frombuf and fromx is what
  981.  *               we set params->xpixels to in SetupScan to make the
  982.  *               main.c module set up zmap right if we're zooming.
  983.  *      tobuf    1 bit monochrome data
  984.  *      tox      width of tox
  985.  *      zmap     Zoom map for impulse zoom
  986.  */
  987.  
  988. static void
  989. RGB16ToMono(void *frombuf, int fromx, void *tobuf, register int tox, int *zmap)
  990. {
  991.     ScaleRowRGB(frombuf, imgTempBuf, fromx);
  992.     RGB8ToMono(imgTempBuf, fromx, tobuf, tox, zmap);
  993. }
  994.  
  995. /*
  996.  *  static void
  997.  *  Grey8ToMono(void *frombuf, int fromx,
  998.  *              void *tobuf, register int tox, int *zmap)
  999.  *
  1000.  *  Description:
  1001.  *      Convert a row of 8 bit/pixel grey scale to a row of 1
  1002.  *      bit/pixel monochrome data, cropping and zooming as necessary.
  1003.  *
  1004.  *  Parameters:
  1005.  *      frombuf  Greyscale image data, 8 bits/pixel
  1006.  *      fromx    In theory, the width of fromx.  In actuality,
  1007.  *               imgStride is the width of frombuf and fromx is what
  1008.  *               we set params->xpixels to in SetupScan to make the
  1009.  *               main.c module set up zmap right if we're zooming.
  1010.  *      tobuf    1 bit monochrome data
  1011.  *      tox      width of tox
  1012.  *      zmap     Zoom map for impulse zoom
  1013.  */
  1014.  
  1015. static void
  1016. Grey8ToMono(void *frombuf, int fromx, void *tobuf, register int tox, int *zmap)
  1017. {
  1018.     char *f = (char *)frombuf + imgOffset;
  1019.     unsigned char *t = tobuf;
  1020.     int x, endx, shift;
  1021.  
  1022.     if (fromx == tox) {
  1023.     while (tox >= 8) {
  1024.         *t++ = THRESH(f[0], THRESHVAL) << 7 |
  1025.         THRESH(f[1], THRESHVAL) << 6 |
  1026.         THRESH(f[2], THRESHVAL) << 5 |
  1027.         THRESH(f[3], THRESHVAL) << 4 |
  1028.         THRESH(f[4], THRESHVAL) << 3 |
  1029.         THRESH(f[5], THRESHVAL) << 2 |
  1030.         THRESH(f[6], THRESHVAL) << 1 |
  1031.         THRESH(f[7], THRESHVAL);
  1032.         tox -= 8;
  1033.         f += 8;
  1034.     }
  1035.  
  1036.     *t = 0;
  1037.     while (tox--) {
  1038.         *t |= THRESH(f[tox], THRESHVAL) << (7 - tox);
  1039.     }
  1040.     } else {
  1041.     endx = tox & ~7;
  1042.     for (x = 0; x < endx; x += 8) {
  1043.         *t++ = THRESH(f[zmap[x]], THRESHVAL) << 7 |
  1044.         THRESH(f[zmap[x + 1]], THRESHVAL) << 6 |
  1045.         THRESH(f[zmap[x + 2]], THRESHVAL) << 5 |
  1046.         THRESH(f[zmap[x + 3]], THRESHVAL) << 4 |
  1047.         THRESH(f[zmap[x + 4]], THRESHVAL) << 3 |
  1048.         THRESH(f[zmap[x + 5]], THRESHVAL) << 2 |
  1049.         THRESH(f[zmap[x + 6]], THRESHVAL) << 1 |
  1050.         THRESH(f[zmap[x + 7]], THRESHVAL);
  1051.     }
  1052.  
  1053.     shift = 7;
  1054.     *t = 0;
  1055.     while (x < tox) {
  1056.         *t |= THRESH(f[zmap[x]], THRESHVAL) << shift;
  1057.         shift--;
  1058.         x++;
  1059.     }
  1060.     }
  1061. }
  1062.  
  1063. /*
  1064.  *  static void
  1065.  *  Grey16ToMono(void *frombuf, int fromx,
  1066.  *              void *tobuf, register int tox, int *zmap)
  1067.  *
  1068.  *  Description:
  1069.  *      Convert a row of 16 bit/pixel grey scale to a row of 1
  1070.  *      bit/pixel monochrome data, cropping and zooming as necessary.
  1071.  *
  1072.  *  Parameters:
  1073.  *      frombuf  Greyscale image data, 16 bits/pixel
  1074.  *      fromx    In theory, the width of fromx.  In actuality,
  1075.  *               imgStride is the width of frombuf and fromx is what
  1076.  *               we set params->xpixels to in SetupScan to make the
  1077.  *               main.c module set up zmap right if we're zooming.
  1078.  *      tobuf    1 bit monochrome data
  1079.  *      tox      width of tox
  1080.  *      zmap     Zoom map for impulse zoom
  1081.  */
  1082.  
  1083. static void
  1084. Grey16ToMono(void *frombuf, int fromx,
  1085.          void *tobuf, register int tox, int *zmap)
  1086. {
  1087.     ScaleRow(frombuf, imgTempBuf, fromx);
  1088.     Grey8ToMono(imgTempBuf, fromx, tobuf, tox, zmap);
  1089. }
  1090.  
  1091. /*
  1092.  * Functions for reading the data from the image file.
  1093.  *
  1094.  * These four functions convert from the coordinate system used by the
  1095.  * scanner interface, which has the origin in the upper left corner of
  1096.  * the image area, to the coordinate system that libimage uses, which
  1097.  * has the origin in the lower left corner of the image area.
  1098.  */
  1099.  
  1100. /*
  1101.  *  static int
  1102.  *  DoGetRows(IMPImage *img, short y, short z, void *buf, int nrows)
  1103.  *
  1104.  *  Description:
  1105.  *      Get rows of image data from an SGI image file.  Used for
  1106.  *      reading from greyscale files and also from rgb files if we're
  1107.  *      converting to planar.
  1108.  *
  1109.  *  Parameters:
  1110.  *      img    SGI image file pointer
  1111.  *      y      y coordinate (in scanner interface coordinates)
  1112.  *      z      z coordinage (0 == red or grey, 1 == green, 2 == blue)
  1113.  *      buf    Buffer that the data will be read into
  1114.  *      nrows  The number of rows to read (currently must be 1)
  1115.  *
  1116.  *  Returns:
  1117.  *      0 if successful, -1 if error
  1118.  */
  1119.  
  1120. /*ARGSUSED*/
  1121. static int
  1122. DoGetRows(IMPImage *img, short y, short z, void *buf, int nrows)
  1123. {
  1124.     short imgy;
  1125.  
  1126.     imgy = impYSize(img) - y - 1;
  1127.     if (impReadRowB(img, buf, imgy, z) == -1) {
  1128.     return -1;
  1129.     }
  1130.     return 0;
  1131. }
  1132.  
  1133. /*
  1134.  *  static int
  1135.  *  DoGetRows16(IMPImage *img, short y, short z, void *buf, int nrows)
  1136.  *
  1137.  *  Description:
  1138.  *      Get rows of image data from an SGI image file.  Used for
  1139.  *      reading from greyscale files and also from rgb files if we're
  1140.  *      converting to planar.
  1141.  *
  1142.  *  Parameters:
  1143.  *      img    SGI image file pointer
  1144.  *      y      y coordinate (in scanner interface coordinates)
  1145.  *      z      z coordinage (0 == red or grey, 1 == green, 2 == blue)
  1146.  *      buf    Buffer that the data will be read into
  1147.  *      nrows  The number of rows to read (currently must be 1)
  1148.  *
  1149.  *  Returns:
  1150.  *      0 if successful, -1 if error
  1151.  */
  1152.  
  1153. /*ARGSUSED*/
  1154. static int
  1155. DoGetRows16(IMPImage *img, short y, short z, void *buf, int nrows)
  1156. {
  1157.     short imgy;
  1158.  
  1159.     imgy = impYSize(img) - y - 1;
  1160.     if (impReadRow(img, buf, imgy, z) == -1) {
  1161.     return -1;
  1162.     }
  1163.     return 0;
  1164. }
  1165.  
  1166. /*
  1167.  *  static int
  1168.  *  DoGetRowsRGB(IMPImage *img, short y, short z, void *buf, int nrows)
  1169.  *
  1170.  *  Description:
  1171.  *      Get rows of image data from an SGI rgb image file.  This is
  1172.  *      used for reading from rgb files if we're converting to rgb
  1173.  *      chunky, greyscale, or monochrome.  We use DoGetRows for rgb
  1174.  *      planar.
  1175.  *
  1176.  *  Parameters:
  1177.  *      img    SGI image file pointer
  1178.  *      y      y coordinate (in scanner interface coordinates)
  1179.  *      z      ignored in this function
  1180.  *      buf    Buffer that the data will be read into
  1181.  *      nrows  The number of rows to read (currently must be 1)
  1182.  *
  1183.  *  Returns:
  1184.  *      0 if successful, -1 if error
  1185.  */
  1186.  
  1187. /*ARGSUSED*/
  1188. static int
  1189. DoGetRowsRGB(IMPImage *img, short y, short z, void *buf, int nrows)
  1190. {
  1191.     short imgy;
  1192.     unsigned char *b = buf;
  1193.  
  1194.     imgy = impYSize(img) - y - 1;
  1195.  
  1196.     if (impReadRowB(img, b, imgy, 0) == -1) { /* red */
  1197.     return -1;
  1198.     }
  1199.  
  1200.     b += impXSize(img);
  1201.     if (impReadRowB(img, b, imgy, 1) == -1) { /* green */
  1202.     return -1;
  1203.     }
  1204.  
  1205.     b += impXSize(img);
  1206.     if (impReadRowB(img, b, imgy, 2) == -1) { /* blue */
  1207.     return -1;
  1208.     }
  1209.  
  1210.     return 0;
  1211. }
  1212.  
  1213. /*
  1214.  *  static int
  1215.  *  DoGetRowsRGB16(IMPImage *img, short y, short z, void *buf, int nrows)
  1216.  *
  1217.  *  Description:
  1218.  *      Get rows of image data from an SGI rgb image file.  This is
  1219.  *      used for reading from rgb files if we're converting to rgb
  1220.  *      chunky, greyscale, or monochrome.  We use DoGetRows for rgb
  1221.  *      planar.
  1222.  *
  1223.  *  Parameters:
  1224.  *      img    SGI image file pointer
  1225.  *      y      y coordinate (in scanner interface coordinates)
  1226.  *      z      ignored in this function
  1227.  *      buf    Buffer that the data will be read into
  1228.  *      nrows  The number of rows to read (currently must be 1)
  1229.  *
  1230.  *  Returns:
  1231.  *      0 if successful, -1 if error
  1232.  */
  1233.  
  1234. /*ARGSUSED*/
  1235. static int
  1236. DoGetRowsRGB16(IMPImage *img, short y, short z, void *buf, int nrows)
  1237. {
  1238.     short imgy;
  1239.     short *b = buf;
  1240.  
  1241.     imgy = impYSize(img) - y - 1;
  1242.  
  1243.     if (impReadRow(img, b, imgy, 0) == -1) { /* red */
  1244.     return -1;
  1245.     }
  1246.  
  1247.     b += impXSize(img);
  1248.     if (impReadRow(img, b, imgy, 1) == -1) { /* green */
  1249.     return -1;
  1250.     }
  1251.  
  1252.     b += impXSize(img);
  1253.     if (impReadRow(img, b, imgy, 2) == -1) { /* blue */
  1254.     return -1;
  1255.     }
  1256.  
  1257.     return 0;
  1258. }
  1259.  
  1260. /*
  1261.  *  int
  1262.  *  SetupScan(SCANPARAMS *params)
  1263.  *
  1264.  *  Description:
  1265.  *      Get ready to perform a scan.  params is a value result
  1266.  *      parameter; it has fields that describe the scanning parameters
  1267.  *      desired by the scanning application, and fields that this
  1268.  *      function is responsible for setting.
  1269.  *
  1270.  *  Parameters:
  1271.  *      params  scanning parameters (in/out)
  1272.  *
  1273.  *  Returns:
  1274.  *      0 if successful, -1 with drverr set if error
  1275.  */
  1276.  
  1277. int
  1278. SetupScan(SCANPARAMS *params)
  1279. {
  1280.     IMPImage *img = params->s->priv;
  1281.  
  1282.     /*
  1283.      * xres and yres will always be 100, because we told main.c that
  1284.      * that is the only resolution we can do in "hardware".  main.c
  1285.      * will set up a zoom map for us later if any zooming needs to
  1286.      * occur.
  1287.      */
  1288.     params->xpixels = params->width * params->xres;
  1289.     params->ylines = params->height * params->yres;
  1290.  
  1291.     if (impRasterBPP(img) == 1) {
  1292.     if (impNumChannels(img) >= 3) {
  1293.         /*
  1294.          * Set xbytes, convert, and imgGetRows appropriately for rgb
  1295.          * image files.
  1296.          */
  1297.         switch (params->type.type) {
  1298.         case SC_RGB:
  1299.         if (params->type.packing == SC_PACKPLANE) {
  1300.             params->xbytes = impXSize(img);
  1301.             params->convert = CropRow8;
  1302.             imgGetRows = DoGetRows;
  1303.         } else {
  1304.             params->xbytes = impXSize(img) * 3;
  1305.             params->convert = RGB8ToChunky8;
  1306.             imgGetRows = DoGetRowsRGB;
  1307.         }
  1308.         break;
  1309.         case SC_GREY:
  1310.         params->xbytes = impXSize(img) * 3;
  1311.         params->convert = RGB8ToGrey8;
  1312.         imgGetRows = DoGetRowsRGB;
  1313.         break;
  1314.         case SC_MONO:
  1315.         params->xbytes = impXSize(img) * 3;
  1316.         params->convert = RGB8ToMono;
  1317.         imgGetRows = DoGetRowsRGB;
  1318.         break;
  1319.         default:
  1320.         drverr = SCEBADTYPE;
  1321.         return -1;
  1322.         }
  1323.     } else {
  1324.         /*
  1325.          * Set xbytes, convert, and imgGetRows appropriately for
  1326.          * greyscale image files.
  1327.          */
  1328.         params->xbytes = impXSize(img);
  1329.         params->convert = params->type.type == SC_GREY ?
  1330.         CropRow8 : Grey8ToMono;
  1331.         imgGetRows = DoGetRows;
  1332.     }
  1333.     } else {
  1334.     if (impNumChannels(img) >= 3) {
  1335.         switch (params->type.type) {
  1336.         case SC_RGB:
  1337.         if (params->type.packing == SC_PACKPLANE) {
  1338.             params->xbytes = impXSize(img) * sizeof (unsigned short);
  1339.             imgGetRows = DoGetRows16;
  1340.             params->convert = params->type.bpp > 8 ?
  1341.             CropRow16 : CropRow16To8;
  1342.         } else {
  1343.             params->xbytes =
  1344.             impXSize(img) * 3 * sizeof (unsigned short);
  1345.             imgGetRows = DoGetRowsRGB16;
  1346.             params->convert = params->type.bpp > 8 ?
  1347.             RGB16ToChunky16 : RGB16ToChunky8;
  1348.         }
  1349.         break;
  1350.         case SC_GREY:
  1351.         params->xbytes = impXSize(img) * 3 * sizeof (unsigned short);
  1352.         imgGetRows = DoGetRowsRGB16;
  1353.         params->convert = params->type.bpp > 8 ?
  1354.             RGB16ToGrey16 : RGB16ToGrey8;
  1355.         break;
  1356.         case SC_MONO:
  1357.         params->xbytes = impXSize(img) * 3 * sizeof (unsigned short);
  1358.         imgGetRows = DoGetRowsRGB16;
  1359.         params->convert = RGB16ToMono;
  1360.         if (imgTempBuf) {
  1361.             free(imgTempBuf);
  1362.         }
  1363.         imgTempBuf = malloc(impXSize(img) * 3);
  1364.         break;
  1365.         }
  1366.     } else {
  1367.         params->xbytes = impXSize(img) * sizeof (unsigned short);
  1368.         imgGetRows = DoGetRows16;
  1369.         if (params->type.type == SC_GREY) {
  1370.         params->convert = params->type.bpp > 8 ?
  1371.             CropRow16 : CropRow16To8;
  1372.         } else {
  1373.         params->convert = Grey16ToMono;
  1374.         if (imgTempBuf) {
  1375.             free(imgTempBuf);
  1376.         }
  1377.         imgTempBuf = malloc(impXSize(img));
  1378.         }
  1379.     }
  1380.     }
  1381.         
  1382.  
  1383.     /*
  1384.      * Set readlines = 1 because at this point that's the only number
  1385.      * of lines that DoGetRows and DoGetRowsRGB supports.  If those
  1386.      * two functions were expanded to do more, than this could be set
  1387.      * higher and everything should work (DoScan already does the
  1388.      * right thing).
  1389.      */
  1390.     params->readlines = 1;
  1391.     imgOffset = params->x * params->xres;
  1392.     imgStride = impXSize(img);
  1393.     return 0;
  1394. }
  1395.  
  1396. /*
  1397.  *  int
  1398.  *  ScanReset(SCANINFO *scan)
  1399.  *
  1400.  *  Description:
  1401.  *      Reset the scanner to its ready state.  This is called after a
  1402.  *      scan has been aborted.  We don't have to do anything here.
  1403.  *
  1404.  *  Parameters:
  1405.  *      scan  Describes the scanner to reset
  1406.  *
  1407.  *  Returns:
  1408.  *      0 if successful, -1 with drverr set if error
  1409.  */
  1410.  
  1411. /*ARGSUSED*/
  1412. int
  1413. ScanReset(SCANINFO *scan)
  1414. {
  1415.     return 0;
  1416. }
  1417.  
  1418. /*
  1419.  *  void
  1420.  *  DoScan(SCANPARAMS *params)
  1421.  *
  1422.  *  Description:
  1423.  *      Perform a scan.  We read the data from the scanner and put it on the
  1424.  *      scan queue so that the image processing process can get it.  This
  1425.  *      function exits when it's done; it's meant to be called via sproc().
  1426.  *
  1427.  *  Parameters:
  1428.  *      params  parameters for the scan
  1429.  */
  1430.  
  1431. void
  1432. DoScan(SCANPARAMS *params)
  1433. {
  1434.     SCANINFO *s = params->s;
  1435.     IMPImage *img = s->priv;
  1436.     void *buf;
  1437.     int toread, curline;
  1438.     int imgy, y, z;
  1439.     int npasses;
  1440.  
  1441.     /*
  1442.      * Exit if our parent dies
  1443.      */
  1444.     prctl(PR_TERMCHILD);
  1445.  
  1446.     y = params->y * params->yres;
  1447.  
  1448.     npasses = params->type.type == SC_RGB &&
  1449.     params->type.packing == SC_PACKPLANE ? 3 : 1; 
  1450.  
  1451.     for (z = 0; z < npasses; z++) {
  1452.     for (curline = 0; curline < params->ylines;
  1453.          curline += params->readlines) {
  1454.         toread = MIN(params->readlines,
  1455.              params->ylines - curline);
  1456.         
  1457.         imgy = y + curline;
  1458.         buf = SCDequeue(params->sfreeq);
  1459.         
  1460.         /*
  1461.          * Get the scan data here!
  1462.          */
  1463.         if ((*imgGetRows)(img, imgy, z, buf, params->readlines) < 0) {
  1464.         drverr = SCEDRVMSG;
  1465.         drvmsg = impErrorString(IMPerrno);
  1466.         exit(1);
  1467.         }
  1468.              
  1469.         /*
  1470.          * Chop the buffer up into scan line sized chunks
  1471.          */
  1472.         while (toread--) {
  1473.         SCEnqueue(params->scanq, buf);
  1474.         buf = (char *)buf + params->xbytes;
  1475.         }
  1476.     }
  1477.     }
  1478.  
  1479.     exit(0);
  1480. }
  1481.  
  1482. /*
  1483.  * These feeder functions should never get called, since we have
  1484.  * denied having a feeder by not setting the feederFlags member of the
  1485.  * SCANINFO struct in OpenScanner.   See the scanner driver template
  1486.  * version of scan.c for comments on what these functions should do if
  1487.  * there really is a feeder attached.
  1488.  */
  1489.  
  1490. /*ARGSUSED*/
  1491. int
  1492. SetFeederFlags(SCANINFO *scan, SCFEEDERFLAGS flags)
  1493. {
  1494.     drverr = SCENOFEEDER;
  1495.     return -1;
  1496. }
  1497.  
  1498. /*ARGSUSED*/
  1499. int
  1500. AdvanceFeeder(SCANINFO *scan)
  1501. {
  1502.     drverr = SCENOFEEDER;
  1503.     return -1;
  1504. }
  1505.  
  1506. /*ARGSUSED*/
  1507. int
  1508. FeederReady(SCANINFO *scan)
  1509. {
  1510.     drverr = SCENOFEEDER;
  1511.     return -1;
  1512. }
  1513.  
  1514. /*
  1515.  *  void
  1516.  *  PrintID(FILE *fp)
  1517.  *
  1518.  *  Description:
  1519.  *      Print a string to fp that describes the type of scanner that
  1520.  *      this driver supports.
  1521.  *
  1522.  *  Parameters:
  1523.  *      fp  stream upon which to print scanner id string
  1524.  */
  1525.  
  1526. void
  1527. PrintID(FILE *fp)
  1528. {
  1529.     fprintf(fp, "SGI Image File\n");   /* String describing scanner */
  1530.     fprintf(fp, "Other");              /* Device type; can be list */
  1531. }
  1532.  
  1533. /*
  1534.  *  void
  1535.  *  FindScanners(FILE *fp)
  1536.  *
  1537.  *  Description:
  1538.  *      Look for scanners that this driver can support.  Since this
  1539.  *      isn't really feasible for SGI image files, we just print
  1540.  *      nothing.
  1541.  *
  1542.  *  Parameters:
  1543.  *      fp  stream upon which to print stuff
  1544.  */
  1545.  
  1546. /*ARGSUSED*/
  1547. void
  1548. FindScanners(FILE *fp)
  1549. {
  1550. }
  1551.  
  1552. /*
  1553.  *  int
  1554.  *  InstallScanner(char *dev)
  1555.  *
  1556.  *  Description:
  1557.  *      This function gets called to implement the "-install" option
  1558.  *      of the driver.  The scanner installation tool wants to install
  1559.  *      a scanner with us as the driver and dev as the device.
  1560.  *
  1561.  *      In our case, "dev" is supposedly an image file.  We make sure
  1562.  *      that we can read it, that iopen can open it, and that it's an
  1563.  *      image file that we understand.
  1564.  *
  1565.  *  Parameters:
  1566.  *      dev   Device to use to install scanner
  1567.  *
  1568.  *  Returns:
  1569.  *      0 if successful, -1 if error.
  1570.  */
  1571.  
  1572. int
  1573. InstallScanner(char *dev)
  1574. {
  1575.     IMPImage *img;
  1576.     SCANINFO *scan;
  1577.  
  1578.     if (access(dev, F_OK | R_OK) != 0) {
  1579.     printf(gettxt(_SGI_FILESCAN_CANTACCESS,
  1580.               "Can't open %s for reading: %s\n"),
  1581.            dev, strerror(errno));
  1582.     return -1;
  1583.     }
  1584.  
  1585.     scan = OpenScanner(dev);
  1586.  
  1587.     if (!scan) {
  1588.     printf("%s\n", drverr == SCEDRVMSG ? drvmsg : SCErrorString(drverr));
  1589.     }
  1590.  
  1591.     return 0;
  1592. }
  1593.  
  1594. /*
  1595.  *  int
  1596.  *  DeleteScanner(char *dev)
  1597.  *
  1598.  *  Description:
  1599.  *      This function gives the scanner driver the opportunity to
  1600.  *      deallocate any resources allocated during InstallScanner, and
  1601.  *      to do any scanner-specific cleanup necessary for deleting a
  1602.  *      scanner.
  1603.  *
  1604.  *  Parameters:
  1605.  *      dev   Device of scanner being deleted
  1606.  *
  1607.  *  Returns:
  1608.  *      0 if successful, -1 if error.
  1609.  */
  1610.  
  1611. /*ARGSUSED*/
  1612. int
  1613. DeleteScanner(char *dev)
  1614. {
  1615.     return 0;
  1616. }
  1617.  
  1618. /*
  1619.  *  void *
  1620.  *  GetSaveOptions(SCANINFO *scan, int *nBytes)
  1621.  *
  1622.  *  Description:
  1623.  *      This function should return to the main.c module a pointer to
  1624.  *      some bytes representing our current settings that we got from
  1625.  *      our scanner specific options program.  If we don't have a
  1626.  *      scanner specific options program, we just set drverr and
  1627.  *      return NULL.
  1628.  *
  1629.  *      The reason for doing this is so that the scanner application
  1630.  *      can save some state for us, and at a later time give us the
  1631.  *      same bytes back so that we can make our state match what it
  1632.  *      was before.
  1633.  *
  1634.  *  Parameters:
  1635.  *      scan    SCANINFO
  1636.  *      nBytes  we fill this in with the number of bytes we're returning
  1637.  *
  1638.  *  Returns:
  1639.  *      pointer to bytes containing scanner specific options settings
  1640.  *      if successful, NULL if error.  drverr must be set to an
  1641.  *      appropriate error code from <scanner.h> or <sys/errno.h> if an
  1642.  *      error occurs.
  1643.  */
  1644.  
  1645. void *
  1646. GetSaveOptions(SCANINFO *scan, int *nBytes)
  1647. {
  1648.     drverr = SCENOSAVEOPT;
  1649.     return NULL;
  1650. }
  1651.  
  1652. /*
  1653.  *  int
  1654.  *  SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
  1655.  *
  1656.  *  Description:
  1657.  *      In this function, the scanner application is restoring state
  1658.  *      that it previously saved after calling GetSaveOptions.  We
  1659.  *      should reset our state to reflect the options passed to us.
  1660.  *
  1661.  *      These are scanner specific settings that were set by our
  1662.  *      scanner specific options program; we don't need to worry about
  1663.  *      things like resolution and scanning area and data type that
  1664.  *      are a part of the standard scanning protocol here.
  1665.  *
  1666.  *  Parameters:
  1667.  *      scan     SCANINFO
  1668.  *      options  the saved settings
  1669.  *      nBytes   number of bytes pointed to by options
  1670.  *
  1671.  *  Returns:
  1672.  *      0 if successful, -1 if error.  drverr must be set to an
  1673.  *      appropriate error code from <scanner.h> or <sys/errno.h> if an
  1674.  *      error occurs.
  1675.  */
  1676.  
  1677. int
  1678. SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
  1679. {
  1680.     drverr = SCENOSAVEOPT;
  1681.     return -1;
  1682. }
  1683.